package com.hjx.movie.core.system.service.admin.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hjx.movie.common.utils.ResultType;
import com.hjx.movie.common.utils.exceptions.CustomException;
import com.hjx.movie.common.utils.tree.TreeBuilder;
import com.hjx.movie.core.security.service.IAuthService;
import com.hjx.movie.core.system.service.admin.IMenuService;
import com.hjx.movie.core.system.service.admin.IRoleMenuService;
import com.hjx.movie.core.system.vo.MenuTreeNode;
import com.hjx.movie.core.util.CombineBeansUtil;
import com.hjx.movie.core.util.cache.CacheKey;
import com.hjx.movie.core.util.cache.CacheUtil;
import com.hjx.movie.persistence.system.mapper.IvyMenuMapper;
import com.hjx.movie.persistence.system.model.IvyMenu;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>Title:</p>
 * <p>Description:</p>
 *
 * @author hjx
 * @date 2021/1/18 - 18:36
 */
@Slf4j
@Service
@Transactional
@CacheConfig(cacheNames = "IvyMovie:SpringCache:MenuCache",keyGenerator = "cacheKeyGenerator")
public class MenuService extends ServiceImpl<IvyMenuMapper, IvyMenu> implements IMenuService {

    @Resource
    private CacheUtil<IvyMenu> cacheUtil;
    @Resource
    private IRoleMenuService roleMenuService;
    @Resource
    private IAuthService authService;

    public static final String MENU_KEY = CacheUtil.cacheNameFormat(CacheKey.SYSTEM.getName(),CacheKey.MENU.getName());
    public static final String MENU_CACHE_DATA = CacheUtil.cacheNameFormat(CacheKey.SYSTEM.getName(),CacheKey.MENU.getName(),CacheKey.PRE_SAVE_MENU.getName());

    // 如果只用Id进行查询 则会以树形返回 如果是带其他查询条件则就不会组装成树，而是直接返回查询结果
    @Override
    @Cacheable(unless = "#result==null")
    public List<MenuTreeNode> selectMenuTree(Long rootMenuId, String menuNameLike, Boolean menuStatus) {
        if (rootMenuId!=null){
            // 从预热的缓存中取出数据
            List<IvyMenu> cacheMenu = cacheUtil.getCacheList(MENU_CACHE_DATA);
            List<IvyMenu> ivyMenus =  cacheMenu.stream().filter(
                    item -> {
                        boolean flag = false;
                        if (item.getMenuId().equals(rootMenuId) || item.getMenuPids().contains(rootMenuId.toString())) {
                            flag = true;
                            if (StringUtils.isNotBlank(menuNameLike)) {
                                flag = item.getMenuPids().contains(menuNameLike);
                            }
                            if (menuStatus!=null&&flag){
                                flag = item.getStatus()==menuStatus;
                            }
                        }
                        return flag;
                    }
            ).collect(Collectors.toList());

            //将List<IvyApi>转换为List<ApiTreeNode>
            List<MenuTreeNode> menuTreeNodes = ivyMenus.stream().map(item->{
                MenuTreeNode node = new MenuTreeNode();
                BeanUtils.copyProperties(item,node);
                return node;
            }).collect(Collectors.toList());
            //如果使用条件查询 会破坏树形结构所以不以树形返回
            if (StringUtils.isNotBlank(menuNameLike)||menuStatus!=null){
                return menuTreeNodes;
            }else {
                return TreeBuilder.builderTreeWidth(menuTreeNodes,rootMenuId);
            }
        }else {
            throw new CustomException(ResultType.USER_INPUT_ERROR,"查询参数的接口id不能为空");
        }
    }

    @CacheEvict(value = "IvyMovie:SpringCache:MenuCache",allEntries=true)
    @Override
    public boolean addMenu(IvyMenu menu) {
        IvyMenu parent = cacheUtil.getCacheData(MENU_CACHE_DATA,menu.getMenuPid().toString());
        Assert.notNull(parent,"找不到此父节点");
        // 将父节点设置为非叶子节点
        parent.setIsLeaf(false);
        menu.setIsLeaf(true);
        // 设置层级
        menu.setLevel(parent.getLevel()+1);
        // 设置所有的"父节点"信息
        menu.setMenuPids(parent.getMenuPids()+",["+menu.getMenuPid()+"]");
        menu.setStatus(menu.getStatus() == null || menu.getStatus());
        boolean result = this.updateById(parent)&&this.save(menu);
        // 新增同时要修改预热的缓存数据
        if (result){
            cacheUtil.getOpsForHash().put(MENU_CACHE_DATA,parent.getMenuId().toString(),parent);
            cacheUtil.getOpsForHash().put(MENU_CACHE_DATA,menu.getMenuId().toString(),menu);
        }
        log.debug("新增接口的ApiId为:{}",menu.getMenuId());
        return result;
    }

    @CacheEvict(value = "IvyMovie:SpringCache:MenuCache",allEntries=true)
    @Override
    public boolean deleteMenu(Long menuId) {
        // 查询出要删除的节点信息
        IvyMenu menu = cacheUtil.getCacheData(MENU_CACHE_DATA,menuId.toString());
        Assert.notNull(menu,"查询不到需要删除的菜单信息");
        Assert.notNull(menu.getMenuPid(),"父节点字段不能为空");
        // 判断自己是不是父节点
        boolean listResult = cacheUtil.getCacheList(MENU_CACHE_DATA).stream()
                .anyMatch(item -> item.getMenuPids().contains(menuId.toString()));

        if (listResult){
            throw new CustomException(ResultType.USER_INPUT_ERROR,"不能删除有子菜单的父级菜单");
        }
        // 查询父节点有几个子节点
        boolean fatherChildren = cacheUtil.getCacheList(MENU_CACHE_DATA)
                .stream()
                .filter(item -> item.getMenuPids().contains(menu.getMenuPid().toString()))
                .count()==1;
        boolean result;
        if (fatherChildren){
            // 进行删除 并且将父节点设置为叶子
            //删除同时要修改预热的缓存数据
            IvyMenu parent = cacheUtil.getCacheData(MENU_CACHE_DATA,menu.getMenuPid().toString());
            parent.setIsLeaf(true);
            result = removeById(menuId)&&updateById(parent);
            if (result){
                cacheUtil.getOpsForHash().put(MENU_CACHE_DATA,parent.getMenuId().toString(),parent);
                cacheUtil.getOpsForHash().delete(MENU_CACHE_DATA,menuId.toString());
            }
        }else {
            result =removeById(menuId);
            if (result){
                cacheUtil.getOpsForHash().delete(MENU_CACHE_DATA,menuId.toString());
            }
        }
        return result;
    }

    @CacheEvict(value = "IvyMovie:SpringCache:MenuCache",allEntries=true)
    @Override
    public boolean updateMenu(IvyMenu menu) {
        // 修改同时要修改预热的缓存数据
        Assert.notNull(menu.getMenuId(),"修改操作必须带主键");
        if (updateById(menu)){
            IvyMenu cacheData = cacheUtil.getCacheData(MENU_CACHE_DATA,menu.getMenuId().toString());
            CombineBeansUtil.combineBean(menu,cacheData);
            log.debug("{}",cacheData);
            cacheUtil.getOpsForHash().put(MENU_CACHE_DATA,menu.getMenuId().toString(),cacheData);
            return true;
        }
        return false;
    }
    @Cacheable(unless = "#result==null")
    @Override
    public List<Long> findMenuExpandedKeys() {
        List<IvyMenu> cacheList = cacheUtil.getCacheList(MENU_CACHE_DATA);
        return cacheList.stream().filter(
                item -> item.getLevel().equals(1) || item.getLevel().equals(2)
        ).map(IvyMenu::getMenuId).collect(Collectors.toList());
    }

    @Override
    public List<Long> findMenuCheckedKeys(Long roleId) {
        return roleMenuService.findMenuByRoleId(roleId);
    }

    @Override
    public List<MenuTreeNode> findLeftMenuAndTabs(String userId) {
        if (StringUtils.isNotBlank(userId)){
            // 从预热的缓存中取出数据
            List<Long> roleIds = authService.findRoleIdByUserId(Long.parseLong(userId));
            List<IvyMenu> ivyMenus = authService.findMenuByRoleId(roleIds);
//            log.debug("============>从缓存中获取到的菜单信息:Start");
//            ivyMenus.forEach(System.out::println);
//            log.debug("============>从缓存中获取到的菜单信息:End");
            Long rootMenuId = 1L;
            for (IvyMenu menu:ivyMenus){
                if (menu.getMenuType().equals("R")){
                    rootMenuId = menu.getMenuId();
                }
            }
            //将List<IvyApi>转换为List<ApiTreeNode>
            List<MenuTreeNode> menuTreeNodes = ivyMenus.stream().map(item->{
                MenuTreeNode node = new MenuTreeNode();
                BeanUtils.copyProperties(item,node);
                return node;
            }).collect(Collectors.toList());

            return TreeBuilder.builderTreeWidthParentId(menuTreeNodes,rootMenuId);

        }else {
            throw new CustomException(ResultType.USER_INPUT_ERROR,"查询参数的用户id不能为空");
        }
    }

}
